package com.semidata.rtd.core.log;

import java.io.File;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import com.semidata.rtd.core.service.SendableService;

public abstract class LogEventHandler implements SendableService<LogEvent> {

    private Thread thread = null;
    private boolean quit = false;
    private LinkedBlockingQueue<LogEvent> queue = new LinkedBlockingQueue<>();
    private LogBlock currentBlock = null;
    private LogBlockHandler handler;
    private String root;

    public LogEventHandler(LogBlockHandler handler) {
        this.handler = handler;
    }

    public boolean setRoot(String root) {
        this.root = root;
        return verify(root);
    }

    @Override
    public void start() {

        thread = new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    try {
                        LogEvent event = queue.poll(1, TimeUnit.SECONDS);
                        if (event == null) {
                            if (quit)
                                break;
                            else {
                                if (currentBlock != null)
                                    handler.send(currentBlock);
                                currentBlock = null;
                                continue;
                            }
                        }
                        log(event);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        thread.start();
    }

    @Override
    public void stop() {
        quit = true;
        try {
            if (thread != null)
                thread.join();
        } catch (InterruptedException e) {
        }
        if (currentBlock != null)
            handler.send(currentBlock);
    }

    @Override
    public void send(LogEvent event) {
        try {
            queue.put(event);
        } catch (InterruptedException e) {
        }
    }

    private void log(LogEvent event) {

        File file = getLogFile(event, root);
        if (file == null)
            return;

        String content = getLogContent(event);
        if (content == null || content.isEmpty())
            return;

        if (currentBlock == null)
            currentBlock = new LogBlock(file);
        else if (currentBlock.getFreeSpace() < content.length() || !currentBlock.getPath().equals(file)) {
            handler.send(currentBlock);
            currentBlock = new LogBlock(file);
        }

        if (currentBlock.getFreeSpace() < content.length())
            return;

        currentBlock.write(content);
        console(content);

    }

    protected abstract File getLogFile(LogEvent event, String root);

    protected abstract String getLogContent(LogEvent event);

    protected abstract boolean verify(String root);

    // if subclass need to print something in console, override this method
    protected void console(String content) {
    }

}
